<template>
	<view class="color-picker-view" :style="pickerViewStyle">
		<view class="color-picker-top">
			<view class="canvas-container">
				<view :style="getCnvasShadow" class="canvas-box" @touchstart="canvasTouchStart" @touchmove="canvasTouchMove" @touchend="canvasTouchEnd">
					<canvas :disable-scroll="true" :style="getCanvasStyle" class="canvas" canvas-id="pickerCanvas"></canvas>
					<cover-view class="canvas-pointer" :style="getCanvasPonterStyle"></cover-view>
				</view>
			</view>
			<view class="slider-container-box" v-show="isLight">
				<text class="opacity">亮度：{{opacity}}%</text>
				<view class="slider-container" :style="sliderStyle" @touchstart="silderTouchStart" @touchmove="silderTouchMove" @touchend="silderTouchEnd">
					<view class="slider-pointer" :style="getSilderStyle"></view>
				</view>
			</view>
		</view>
		<view v-if="isAddColor" class="palletes-container" :style="getPalletesStyle">
			<view v-for="(color, index) in historyColors" :key="index" @click="colorItemClick(index)" @longpress="longpress(index)"
			 :class="{scale: index == selectColorIndex}" class="palette" :style="'background:' + color + ';width: '+palletesWidth+'px;height: '+palletesWidth+'px'"></view>
			<view v-if="!disabledAdd" class="palette add" @touchend="add" :style="'width: '+(palletesWidth - 4)+'px;height: '+(palletesWidth - 4)+'px'"></view>
		</view>
	</view>
</template>

<script>
	import {
		HEX_REG,
		HEXtoRGB,
		RGBtoHSV,
		RGBtoHEX,
		HSVtoRGB,
		$,
		nodeInfo,
		queryCanvas,
		scientificToArtisticSmooth,
		makeGradient,
		praseEventPos
	} from "@/components/color-picker/uils.js"
	export default {
		name: 'color-picker',
		props: {
			'default-colors': {
				type: Array,
				default: []
			},
			'disabled-add': { //禁用添加
				type: Boolean,
				default: false
			},
			'is-add-color': { // 是否显示默认配色
				type: Boolean,
				default: true
			},
			'picker-width': { //彩色圆盘的大小
				type: Number,
				default: 280
			},
			'light-to-color': { //明度改变影响所有颜色, 会影响性能
				type: Boolean,
				default: false
			},
			height: Number,
			'local-storage': { //是否存储已经选择的颜色
				type: Boolean,
				default: false
			},
			'local-storage-id': { //存储的key 只有在 localStorage: true 有效
				type: String,
				default: 'storage-id'
			},
			'is-light': { // 是否显示亮度调节功能
				type: Boolean,
				default: true
			},
		},
		data() {
			return {
				src: '/static/color.png',
				opacity: 0,
				selectColorIndex: 0,
				historyColors: [],
				sliderLeft: 0, //透明度的滑块
				canvasPonterPos: { //选色板的滑块
					x: 0,
					y: 0,
				},
				topContent: null,
				sliderStyle: '',
				colors: {},
				showColor: {}, ///只用于显示的颜色
				currentColor: '',
				R: 'rgb(255, 0, 0)',
				G: 'rgb(0, 255, 0)',
				B: 'rgb(0, 0, 255)',
				palletesWidth: 45
			};
		},
		computed: {
			pickerViewStyle() {
				return `height: ${this.height || ''}px`
			},
			getCanvasStyle() {
				return `width: ${this.pickerWidth || 280}px;height: ${this.pickerWidth || 280}px`
			},
			getCnvasShadow() {
				return `box-shadow: 0 0 20px 5px ${this.colors.hex};width: ${(this.pickerWidth || 280) - 1}px;height: ${(this.pickerWidth || 280) - 1}px`
			},
			getSilderStyle() {
				return `left: ${this.sliderLeft}px`
			},
			getCanvasPonterStyle() {
				return `left: ${this.canvasPonterPos.x}px;top: ${this.canvasPonterPos.y}px`
			},
			getColors() {
				return `background: ${this.colors.hex}`
			},
			RStyle() {
				return `background: ${this.R}`
			},
			GStyle() {
				return `background: ${this.G}`
			},
			BStyle() {
				return `background: ${this.B}`
			},
			getPalletesStyle() {
				let top = this.isLight ? 20 : 50;
				return `margin-top: ${top}px;height: calc(100% - ${this.topContent ? (this.topContent.height + top) + 'px' : '72%'})`
			}
		},
		mounted() {
			this.init();
		},
		methods: {
			//初始化
			async init() {
				let colorArr = this.defaultColors;
				if(this.localStorage){
					let colors = uni.getStorageSync(this.localStorageId);
					if (colors) {
						colors = JSON.parse(colors);
						colorArr = [...colorArr, ...colors];
					}
				}
				this.historyColors = Array.from(new Set([...colorArr]));
				this.localStorage && this.saveColors();
				this.currentColor = this.historyColors[this.selectColorIndex];
				//获取元素的信息
				this.topContent = await nodeInfo.call(this, '.color-picker-top');
				this.slider = await nodeInfo.call(this, '.slider-container');
				this.sliderPointer = await nodeInfo.call(this, '.slider-pointer');
				this.canvas = await nodeInfo.call(this, '.canvas');
				this.poiner = await nodeInfo.call(this, '.canvas-pointer');
				this.palletes = await nodeInfo.call(this, '.palletes-container');
				this.palletesWidth = (this.palletes.width - 60) / 6 - 7

				//初始化颜色
				this.updateColor(HEXtoRGB(this.currentColor));

				//获取canvas 坐标信息
				this.initCanvasBounds();

				//绘制画布
				this.redrawCanvas();

				this.updateCoordinates(this.canvasBounds.centerX, this.canvasBounds.centerY);
				const coordinates = this.getPositionFromColor(this.currentColor);
				if (coordinates) {
					this.x = coordinates.x;
					this.y = coordinates.y;
				}
				this.redrawSlider();
				this.updatePointers();
				this.updateSlider();
			},
			//更新颜色
			updateColor(pixel) {
				this.hex = RGBtoHEX(...pixel);
				this.hsv = RGBtoHSV(...pixel);
				this.rgb = [...pixel];
				//1.显示值
				this.setColors();
			},

			//绘制画布
			redrawCanvas() {
				const {width, height, radius} = this.canvasBounds;
				let ctx = this.ctx = uni.createCanvasContext('pickerCanvas', this);
				ctx.drawImage(this.src, 0, 0, width, height)
				ctx.draw();
			},

			//获取canvas 坐标信息
			initCanvasBounds() {
				const radius = this.canvas.width / 2;
				this.canvasBounds = {
					...this.canvas,
					radius,
					centerX: this.canvas.left + radius,
					centerY: this.canvas.top + radius,
				}
				this.pointerBounds = {
					...this.poiner,
					radius: this.poiner.width / 2
				}

				this.sliderBounds = {
					...this.slider,
					radius: this.slider.width / 2,
				}
				this.sliderPoierBounds = {
					...this.sliderPointer,
					radius: this.sliderPointer.width / 2,
				}
			},

			//计算当前坐标
			updateCoordinates(x, y) {
				const {
					centerX,
					centerY,
					radius,
					left,
					top
				} = this.canvasBounds;
				const pradius = this.pointerBounds.radius
				const angle = Math.atan2(y - centerY, x - centerX);
				const r = Math.sqrt(Math.pow(x - centerX, 2) + Math.pow(y - centerY, 2));
				const vr = radius - 1;
				if (r > vr) {
					x = Math.cos(angle) * vr + centerX;
					y = Math.sin(angle) * vr + centerY;
				}
				this.x = Math.floor(x - left);
				this.y = Math.floor(y - top);
			},

			//通过颜色计算位置
			getPositionFromColor(color) {
				color = HEXtoRGB(color);
				if (color == null) return null;
				this.hsv = RGBtoHSV(...color);
				return this.getSVGPositionFromHS(...this.hsv);
			},
			getSVGPositionFromHS(h, s) {
				const {
					centerX,
					centerY,
					radius,
					left,
					top
				} = this.canvasBounds;
				let hue = scientificToArtisticSmooth(h * 360);
				let angle = hue * (Math.PI / 180);
				let x = Math.cos(angle) * radius * s;
				let y = Math.sin(angle) * radius * s;
				return {
					x:  x + radius,
					y: radius - y
				}
			},

			//获取透明度渐变背景样式
			redrawSlider() {
				let color = this.currentColor;
				let gradient = makeGradient(color, '#000000');
				this.sliderStyle = gradient;
			},
			//更新滑块
			updateSlider() {
				let x = (this.slider.width * this.hsv[2]) + (this.slider.left + 1 + this.sliderPoierBounds.radius)
				this.setSliderPointerValue(x, 0);
			},

			//更新canvas上的滑块
			updatePointers() {
				const {
					radius
				} = this.pointerBounds;
				this.canvasPonterPos = {
					x: this.x - radius,
					y: this.y - radius
				}
			},

			setColors(colors) {
				this.colors = colors || {
					hex: this.hex,
					hsv: this.hsv,
					rgb: this.rgb
				}
			},
			
			debounce(fn, delay = 500){
				this.timer && clearTimeout(this.timer);
				this.timer = setTimeout(fn, delay)
			},

			onChange() {
				this.$emit('change', this.colors)
			},

			//获取canvas上的颜色
			getCanvasPosColor(clientX, clientY) {
				this.updateCoordinates(clientX, clientY);
				this.updatePointers();
				uni.canvasGetImageData({
					canvasId: 'pickerCanvas',
					x: this.x,
					y: this.y,
					width: 1,
					height: 1,
					success: res => {
						//初始化颜色
						this.updateColor(res.data);
						//透明度滑条
						this.currentColor = this.hex;
						this.redrawSlider();
						// this.onChange();
					},
					fail(err) {}
				}, this)
			},
			
			//画布的拖拽操作
			canvasTouchStart(e) {
				this.getCanvasPosColor(...praseEventPos(e));
			},
			canvasTouchMove(e) {
				this.getCanvasPosColor(...praseEventPos(e))
			},
			canvasTouchEnd(){
				 this.onChange();
			},
			//透明度的拖拽操作
			silderTouchStart(e) {
				this.setSliderPointerValue(...praseEventPos(e))
			},

			silderTouchMove(e) {
				this.setSliderPointerValue(...praseEventPos(e))
			},
			silderTouchEnd(){
				this.$emit('light-change', {
					percent: this.opacity,
					value: this.lightnessValue
				})
			},
			setSliderPointerValue(clientX, clientY, bool) {
				let {
					width,
					left
				} = this.slider;
				let sb = this.sliderPoierBounds;
				let x = clientX - left - sb.radius;

				let sw = width - sb.width;
				if (x <= 0) {
					x = 0;
				} else if (x >= sw) {
					x = sw;
				}
				this.lightnessValue = x / sw;
				this.opacity = parseInt(this.lightnessValue * 100)
				this.sliderLeft = x;
			},
			lightnessToColor(light) {
				let hsv = [...this.hsv];
				hsv[2] = light;
				let rgb = HSVtoRGB(...hsv);
				let hex = RGBtoHEX(...rgb);
				return {
					hsv,
					hex,
					rgb
				}
			},
			//添加历史颜色
			add() {
				this.historyColors = [...this.historyColors, this.currentColorLight || this.currentColor];
				this.localStorage && this.saveColors();
			},
			saveColors() {
				uni.setStorage({
					key: this.localStorageId,
					data: JSON.stringify(this.historyColors),
					success: function() {}
				});
			},
			colorItemClick(index) {
				this.selectColorIndex = index;
				this.currentColor = this.historyColors[this.selectColorIndex];

				this.updateColor(HEXtoRGB(this.currentColor));
				this.redrawSlider();
	
				const coordinates = this.getPositionFromColor(this.currentColor);
				if (coordinates) {
					this.x = coordinates.x;
					this.y = coordinates.y;
				}
				this.redrawSlider();
				this.updatePointers();
				this.onChange();
			},
			longpress(index) {
				if (this.disabledAdd) return;
				this.historyColors.splice(index, 1);
				this.$forceUpdate();
				this.localStorage && this.saveColors();
			}
		}
	}
</script>

<style>
	.uni-body uni-page-wrapper {
		overflow: hidden !important;
	}

	.color-picker-top {
		padding: 30px 0 0 0;
	}

	.canvas-image {
		width: 100%;
		height: 100%;
	}

	.color-picker-view {
		width: 100vw;
		background: transparent;
		overflow: hidden;
	}

	.canvas-container {
		background: transparent;
		margin: 0 auto;
		position: relative;
	}

	.canvas-box {
		width: 280px;
		height: 280px;
		-webkit-border-radius: 50%;
		border-radius: 50%;
		-webkit-box-shadow: 0 0 0 3px #E8E8E8;
		box-shadow: 0 0 0 3px #E8E8E8;
		background: transparent;
		margin: 0 auto;
		position: relative;
	}

	.canvas {
		width: 280px;
		height: 280px;
		-webkit-border-radius: 50%;
		border-radius: 50%;
	}

	.slider-container-box {
		padding-top: 40px;
	}

	.slider-container {
		position: relative;
		margin: 15px 25px 0;
		height: 15px;
		background: red;
		-webkit-border-radius: 10px;
		border-radius: 10px;
		border: 1px solid #b1b1b1;
	}

	.opacity {
		display: inline-block;
		text-align: center;
		width: 100%;
		color: #fff;
	}

	.slider-pointer,
	.canvas-pointer {
		display: inline-block;
		position: absolute;
		left: 0;
		top: 0;
		border: 3px solid #fff;
		-webkit-border-radius: 50%;
		border-radius: 50%;
		background: transparent;
		-webkit-box-sizing: content-box;
		box-sizing: content-box;
	}

	.canvas-pointer {
		width: 10px;
		height: 10px;
		border: 3px solid #7d7d7d;
		-webkit-box-shadow: 0px 0px 0px 2px rgb(10 10 10 / 28%);
		box-shadow: 0px 0px 0px 2px rgb(10 10 10 / 28%);
	}

	.canvas-pointer::after {
		content: "";
		position: absolute;
		width: 2px;
		height: 2px;
		background: #7d7d7d;
		-webkit-border-radius: 50%;
		border-radius: 50%;
		-webkit-transform: translate(-50%, -50%);
		transform: translate(-50%, -50%);
		left: 50%;
		top: 50%;
	}

	.slider-pointer {
		width: 12px;
		height: 12px;
		top: -2px;
		-webkit-box-shadow: 0px 0px 3px 3px #cacacaf2;
		box-shadow: 0px 0px 1px 3px #cacacaf2;
	}

	.palletes-container {
	    overflow-x: hidden;
	    overflow-y: auto;
	    padding: 0 20px;
	    text-align: center;
	
	}

	.palette {
		float: left;
		border-radius: 4px;
		margin: 5px 5px;
		box-shadow: inset 0px 2px 1px rgba(0, 0, 0, 0.28);
		transition: all .2s ease-in-out;
		box-sizing: content-box;
	}

	.palette.active {
		-webkit-box-shadow: 0 0 2px 4px #3333338c;
		box-shadow: 0 0 2px 4px #3333338c;
	}

	.palette.add {
		border: 2px dashed #bababa;
		-webkit-box-shadow: inherit;
		box-shadow: inherit;
		position: relative;
	}

	.palette.add::after {
		content: '+';
		font-size: 24px;
	    color: #bababa;
	    position: absolute;
	    left: 50%;
	    top: 50%;
	    transform: translate(-50%, -50%);
	}

	.colors-box {
		margin: 30px 20px 0;
	}

	.colors-box .colors {
		padding: 3px 5px;
		font-size: 12px;
		-webkit-border-radius: 12px;
		border-radius: 12px;
		color: #00000
	}

	.RGB-box {
		border: 1px solid #fff;
		-webkit-border-radius: 4px;
		border-radius: 4px;
		display: inline-block;
		width: 45px;
		height: auto;
		padding: 0px 1px;
	}

	.RGB-item {
		display: -webkit-box;
		display: -webkit-flex;
		display: flex;
		-webkit-box-orient: horizontal;
		-webkit-box-direction: normal;
		-webkit-flex-direction: row;
		flex-direction: row;
		-webkit-box-align: center;
		-webkit-align-items: center;
		align-items: center;
		margin: 1px 0;
		font-size: 12px;
		height: 14px;
		line-height: 14px;
	}

	.RGB-item-key {
		width: 13px;
		text-align: center;
		color: #fff;
		-webkit-border-radius: 2px;
		border-radius: 2px;
	}

	.RGB-item-value {
		-webkit-box-flex: 1;
		-webkit-flex: 1;
		flex: 1;
		text-align: center;
		color: #fff;
		-webkit-border-radius: 2px;
		border-radius: 2px;
		margin-left: 2px;
	}

	.scale {
		animation: scale .3s alternate-reverse;
	}

	@-webkit-keyframes scale {
		0% {
			-webkit-transform: scale(1);
			transform: scale(1);
		}

		100% {
			-webkit-transform: scale(1.1);
			transform: scale(1.1);
		}
	}

	@keyframes scale {
		0% {
			-webkit-transform: scale(1);
			transform: scale(1);
		}

		100% {
			-webkit-transform: scale(1.1);
			transform: scale(1.1);
		}
	}
</style>
